import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import random
import seaborn as sns

# 导入数据
filepath=r'C:\Users\86186\Downloads\house.csv'
df = pd.read_csv(filepath, encoding='gbk')

#初步探索性结果
print(f'样本量共有 {df.shape[0]} 个')
#判断是否有重复项
print("重复项：\n",df.duplicated().sum())
#判断是否有缺失值
print("缺失值：\n",df.isnull().sum())
#查看数据类型
print("数据类型：\n",df.dtypes)
#唯一标签值
print(df['朝向'].unique())
print(df['楼层'].unique())
print(df['装修'].unique())
print(df['产权性质'].unique())
print(df['住宅类别'].unique())
print(df['建筑结构'].unique())
print(df['建筑类别'].unique())
print(df['区域'].unique())
print(df['建筑年代'].unique())



#数据清洗
##数据格式转换
df.replace('暂无',np.nan,inplace=True)
df['建筑面积'] = df['建筑面积'].map(lambda x: x.replace('平米','')).astype('float')
df['单价'] = df['单价'].map(lambda x: x.replace('元/平米','')).astype('float')
def process_year(year):
    if year is not None:
        year = str(year)[:4]
    return year
df['建筑年代'] = df['建筑年代'].map(process_year)
floor = {'低楼层': '低','中楼层': '中','高楼层': '高','低层': '低','中层': '中','高层': '高'}
df['楼层'] = df['楼层'].map(floor)
def process_area(area):
    if area != '新区':
        area = area.replace('区','').replace('县','')
    return area
df['区域'] = df['区域'].map(process_area)
df.replace('nan',np.nan,inplace=True)

##重复值处理
df.drop_duplicates(inplace=True)
df.reset_index(drop=True, inplace=True)

##缺失值处理
df.info()
# 户型、朝向、楼层处理，缺失值数量不多，考虑直接删除即可
df.dropna(subset=['户型','朝向','楼层'], inplace=True)
# 建筑年代、建筑类别、建筑结构、住宅类别、产权性质、装修 这些离散型变量很难处理，得根据实际情况填充，为了得到更加真实的结果暂不处理
# 电梯处理（底层无，高层有，中层随机处理）
df.loc[(df['楼层'] == '高') & (df['电梯'].isnull()),'电梯'] = '有 '
df.loc[(df['楼层'] == '低') & (df['电梯'].isnull()),'电梯'] = '无 '
df.loc[(df['楼层'] == '中') & (df['电梯'].isnull()),'电梯'] = random.choice(['有 ','无 '])
df.reset_index(drop=True, inplace=True)

##异常值处理
###箱型图（了解建筑面积和总价的数据分布情况
plt.rcParams['font.sans-serif'] = ['SimHei']                 #设置字体
plt.rcParams['axes.unicode_minus'] = False                   #确保负号可以正常显示
fig1,ax = plt.subplots(1,2,figsize=(16,6))       #创建了两个水平方向上的子图
df.boxplot(column=['建筑面积'], flierprops={'markeredgecolor':'red', 'markersize':4}, ax=ax[0])
df.boxplot(column=['总价'], flierprops={'markeredgecolor':'red', 'markersize':4}, ax=ax[1])   #异常值边缘标红处理
print("箱型图：\n")
plt.show()
print(df.describe())
#将总价高于上限的当作异常值进行处理（直接删除法），考虑大多数人可购买的情况。
df.drop(index=df[df['总价'] > 200].index, inplace=True)
##另存新文件
df.to_excel('house.xlsx',index=False)




#数据分析
##探究单价、数量、总价和行政区域之间的关系
fig2,ax = plt.subplots(3,1,figsize=(8,18))           #创建三个竖直方向上的子图
x = df['区域'].unique()                                           #x轴统一为区域
###各区单价对比
y1 = round(df.groupby(by=['区域'])['单价'].mean().sort_values(ascending=False),2)           #y轴为各区平均单价
sns.barplot(x=x,y=y1,ax=ax[0],palette='Blues_r')                                          #颜色为从深蓝色到浅蓝色的渐变
ax[0].set_title('兰州各县\区二手房平均单价对比')
ax[0].set_ylabel('单价')
ax[0].set_xlabel('区域')
###各区总价对比
y2 = round(df.groupby(by=['区域'])['总价'].mean().sort_values(ascending=False),2)          #y轴为各区平均总价
sns.barplot(x=x,y=y2,ax=ax[1],palette='Reds_r')                                          #颜色为从深红色到浅红色的渐变
ax[1].set_title('兰州各县\区二手房平均总价对比')
ax[1].set_ylabel('总价')
ax[1].set_xlabel('区域')
###各区房子数量对比
y3 = round(df.groupby(by=['区域']).size().sort_values(ascending=False),2)                 #y轴为各区平均数量
sns.barplot(x=x,y=y3,ax=ax[2],palette='Oranges_r')                                       #颜色为从深黄色到浅黄色的渐变
ax[2].set_title('兰州各县\区二手房数量对比')
ax[2].set_ylabel('数量')
ax[2].set_xlabel('区域')
plt.show()

##探究面积和总价的关系
plt.figure(figsize=(8,7))
plt.title('建筑面积与总价的散点分布')
sns.scatterplot(x='建筑面积',y='总价',data=df,s=14)
plt.show()

##探究楼层和总价的关系
plt.figure(figsize=(10,8))
plt.title('楼层与总价的关系（箱线图）')
my_order = df.groupby(by=["楼层"])["总价"].median().sort_values(ascending=False).index          # 根据'楼层'分组，计算'总价'的中位数，并按照中位数降序排序
sns.boxplot(x='楼层',y='总价',data=df,width=0.3,notch=True,order=my_order)
plt.show()

##探究电梯和总价的关系
plt.figure(figsize=(10,8))
plt.title('是否有电梯与总价的关系（箱线图）')
my_order = df.groupby(by=["电梯"])["总价"].median().sort_values(ascending=False).index          #根据是否有电梯分组，计算总价的中位数、并按照中位数降序排列
sns.boxplot(x='电梯',y='总价',data=df,width=0.2,notch=True,order=my_order)
plt.show()

##探究学区房和总价的关系
plt.figure(figsize=(10,8))
plt.title('学区房与总价的关系（箱线图）')
my_order = df.groupby(by=["学校"])["总价"].median().sort_values(ascending=False).index          #根据是否是学区房分组，计算总价的中位数、并按照中位数降序排列
sns.boxplot(x='学校',y='总价',data=df,width=0.2,notch=True,order=my_order)
plt.show()

##建筑年代情况分析
plt.figure(figsize=(16,8))
plt.title('不同年份的二手房数量情况')
order = sorted(df['建筑年代'].value_counts().index)                             #将年份升序排列
sns.countplot(x=df['建筑年代'],order=order)
plt.show()
###建筑年代和总价的关系
plt.figure(figsize=(13,8))
plt.title('二手房数量前二十的年份总价情况（箱线图）')
my_order = df.groupby(by=["建筑年代"])["总价"].size().sort_values(ascending=False).index[:20]    #对于不同年份的二手房数量进行降序排序并取前二十位（这里只通过总价计算二手房数量）
sns.boxplot(x='建筑年代',y='总价',data=df,width=0.2,notch=True,order=my_order)
plt.show()